<?php
namespace Snitso\IO\Multiplexing;

class Worker
{
    /**
     * @var resource $socket
     */
    protected $socket;

    /**
     * @var \Closure
     */
    public $onConnect;

    /**
     * @var \Closure
     */
    public $onReceive;

    /**
     * @var array 连接池
     */
    protected $sockets = [];

    public function __construct(string $localSocket)
    {
        $this->socket = stream_socket_server($localSocket, $errno, $errstr);

        if (! $this->socket) {
            echo $errstr . PHP_EOL;
            exit;
        }

        stream_set_blocking($this->socket, 0);

        $this->sockets[(int)$this->socket] = $this->socket;

        $this->debug(111, $this->sockets);
    }

    public function start()
    {
        $this->accept();
    }

    protected function accept()
    {
        while (true) {
            $this->debug('走这里了');

            sleep(1);

            $read = $this->sockets;
            $w = $e = null;

            // stream_socket_server 会创建一个连接，等待新的连接进来
            // 这个连接也有忙的时候，所以第二次输出时只有一个连接
            // 检测可读资源
            stream_select($read, $w, $e, 1);

            $this->debug(222, $read);

            foreach ($read as $socket) {
                // 刚刚进来的连接
                // 通过 stream_socket_accept 创建
                if ($socket == $this->socket) {
                    $this->createSocket();
                } else {
                    $this->sendMsg($socket);
                }
            }
        }
    }

    /**
     * Note: 创建一个新的 socket 连接
     *
     * @author: Zhao Zhiqiang
     * @since: 2021/4/30 16:26
     */
    protected function createSocket()
    {
        $conn = stream_socket_accept($this->socket);

        if ($conn === false) {
            echo '连接失败' . PHP_EOL;
            exit;
        }

        ($this->onConnect)($this, $conn);

        $this->sockets[(int)$conn] = $conn;

        $this->debug(333, $this->sockets);
    }

    /**
     * Note: 发送和接收消息
     *
     * @param $conn
     * @author: Zhao Zhiqiang
     * @since: 2021/4/30 16:29
     */
    public function sendMsg($conn)
    {
        $this->debug(444, $conn);

        $data = fread($conn, 1024);

        if ($data === '') {
            fclose($conn);
            unset($this->sockets[(int)$conn]);

            return;
        }

        ($this->onReceive)($this, $conn, $data);
    }

    public function send($conn, string $content)
    {
        $response = "HTTP/1.1 200 OK\r\n";
        $response .= "Content-Type: text/html;charset=UTF-8\r\n";
        $response .= "Connection: keep-alive\r\n";
        $response .= "Content-length: ".strlen($content)."\r\n\r\n";
        $response .= $content;
        fwrite($conn, $response);
    }

    protected function debug(string $str, $data = null)
    {
        echo $str . PHP_EOL;

        if ($data) {
            print_r($data);
            echo "\r\n";
        }
    }
}